using System;
using FireStarterModeller.BO;
using FireStarterModeller.Test.BO;
using FireStarterModeller.UI;
using Habanero.Base;
using Habanero.Faces.Base;
using Habanero.Faces.Win;
using NUnit.Framework;

namespace FireStarterModeller.Test.UI.Relationships
{
    [TestFixture]
    public class TestDMRelatedPropertiesControl 
    {
        [TestFixtureSetUp]
        public void SetupFixture()
        {
            UITestUtils.SetupFixture();
        }

        [SetUp]
        public virtual void SetupTest()
        {
            UITestUtils.SetupTest();

        }

        private static void AssertColumnComboBoxItems(int expectedItemCount, DMRelatedPropertiesControl actualControl, string columnName)
        {
            Assert.IsTrue(actualControl.SelectorAndBOEditorControl.Grid.Columns.Contains(columnName));
            IDataGridViewColumn column = actualControl.SelectorAndBOEditorControl.Grid.Columns[columnName];
            Assert.IsInstanceOf(typeof(IDataGridViewComboBoxColumn), column);
            IDataGridViewComboBoxColumn comboBoxColumn = (IDataGridViewComboBoxColumn)column;
            Assert.IsNotNull(comboBoxColumn.DataSource);
            Assert.AreEqual(expectedItemCount, comboBoxColumn.Items.Count, "Count of the items in the combo box column was expected to be " + expectedItemCount);
        }

        [Test]
        public void Test_Construction_NullControlFactory_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------

            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            try
            {
                new DMRelatedPropertiesControl(null);
                Assert.Fail("expected ArgumentNullException");
            }
                //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("", ex.ParamName);
            }
        }

        [Test]
        public void TestConstruction()
        {
            //---------------Set up test pack-------------------

            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            DMRelatedPropertiesControl control = new DMRelatedPropertiesControl(new ControlFactoryWin());
            //---------------Test Result -----------------------
            Assert.IsInstanceOf(typeof(UserControlWin), control);
            Assert.IsInstanceOf(typeof(IFormControl), control);
            Assert.AreEqual(1, control.Controls.Count);
            Assert.IsInstanceOf(typeof(IGridControl), GetGridControl(control));
            IGridControl gridControl = GetGridControl(control);
            Assert.IsFalse(gridControl.FilterControl.Visible);
            Assert.IsFalse(gridControl.Buttons["Save"].Visible);
        }

        private IGridControl GetGridControl(DMRelatedPropertiesControl control)
        {
            return (IGridControl) control.Controls[0].Controls[0];
        }

        [Test]
        public void TestSetRelationship_LoadsRelatedPropertyInfos()
        {
            //---------------Set up test pack-------------------
            DMRelationship relationship = TestUtilsShared.CreateSavedRelationshipInfoWithTwoRelatedProperties();
            DMRelatedPropertiesControl control = new DMRelatedPropertiesControl(new ControlFactoryWin());
            IGridControl gridAndBOEditorControl = GetGridControl(control);
            //---------------Assert Precondition----------------
            Assert.GreaterOrEqual(relationship.RelationshipProperties.Count, 1);
            //---------------Execute Test ----------------------
            control.Relationship = relationship;
            //---------------Test Result -----------------------
            Assert.AreSame(relationship, control.Relationship);
            Assert.AreSame(relationship, control.BusinessObject);
            IBusinessObjectCollection boCollection = gridAndBOEditorControl.BusinessObjectCollection;
            Assert.AreSame(boCollection, relationship.RelationshipProperties);
            Assert.AreSame(boCollection, control.BusinessObjectCollection);
            Assert.AreEqual(boCollection.Count, relationship.RelationshipProperties.Count);
        }

        [Test]
        public void TestSetRelationship_ToNull_LoadsEmptyCollection()
        {
            //---------------Set up test pack-------------------
            DMRelatedPropertiesControl control = new DMRelatedPropertiesControl(new ControlFactoryWin());
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            control.Relationship = null;
            //---------------Test Result -----------------------
            Assert.IsNull(control.Relationship);
            Assert.IsNull(control.BusinessObject);
            Assert.AreEqual(0, control.BusinessObjectCollection.Count);
        }

        [Test]
        public void TestSetBusinessObject_LoadsRelatedPropertyInfos()
        {
            //---------------Set up test pack-------------------
            DMRelationship relationship = TestUtilsShared.CreateSavedRelationshipInfoWithTwoRelatedProperties();
            DMRelatedPropertiesControl control = new DMRelatedPropertiesControl(new ControlFactoryWin());
            IGridControl gridAndBOEditorControl = GetGridControl(control);
            //---------------Assert Precondition----------------
            Assert.GreaterOrEqual(relationship.RelationshipProperties.Count, 1);
            //---------------Execute Test ----------------------
            control.BusinessObject = relationship;
            //---------------Test Result -----------------------
            Assert.AreSame(relationship, control.Relationship);
            Assert.AreSame(relationship, control.BusinessObject);
            IBusinessObjectCollection boCollection = gridAndBOEditorControl.BusinessObjectCollection;
            Assert.AreSame(boCollection, relationship.RelationshipProperties);
            Assert.AreSame(boCollection, control.BusinessObjectCollection);
            Assert.AreEqual(boCollection.Count, relationship.RelationshipProperties.Count);
        }

        [Test]
        public void TestSetBusinessObject_ToNull_LoadsEmptyCollection()
        {
            //---------------Set up test pack-------------------
            DMRelatedPropertiesControl control = new DMRelatedPropertiesControl(new ControlFactoryWin());
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            control.BusinessObject = null;
            //---------------Test Result -----------------------
            Assert.IsNull(control.BusinessObject);
            Assert.IsNull(control.Relationship);
            Assert.AreEqual(0, control.BusinessObjectCollection.Count);
        }

        [Test]
        public void TestDisabledAtCreation()
        {
            //---------------Execute Test ----------------------
            DMRelatedPropertiesControl control =
                new DMRelatedPropertiesControl(new ControlFactoryWin());
            //---------------Test Result -----------------------

            Assert.IsFalse(control.Enabled);
        }

        [Test]
        public void TestSetBusinessObject_EnablesControl()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = TestUtilsShared.CreateSavedRelationshipInfoWithTwoRelatedProperties();
            DMRelatedPropertiesControl control =
                new DMRelatedPropertiesControl(new ControlFactoryWin());

            //---------------Execute Test ----------------------
            control.Relationship = dmRelationship;
            //---------------Test Result -----------------------
            Assert.IsTrue(control.Enabled);
        }

        [Test]
        public void TestSetBusinessObject_ToNull_DisablesControl()
        {
            //---------------Set up test pack-------------------
            DMRelationship info = TestUtilsShared.CreateSavedRelationshipInfoWithTwoRelatedProperties();
            DMRelatedPropertiesControl control = new DMRelatedPropertiesControl(new ControlFactoryWin());
            control.Relationship = info;
            //---------------Execute Test ----------------------
            control.Relationship = null;
            //---------------Test Result -----------------------
            Assert.IsFalse(control.Enabled);
        }

        [Test]
        public void TestSetBusinessObject_SetsPermissionOnEditorControl()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = TestUtilsShared.CreateSavedRelationshipInfoWithTwoRelatedProperties();
            DMRelatedPropertiesControl control =
                new DMRelatedPropertiesControl(new ControlFactoryWin());
            //---------------Assert Precondition----------------
            Assert.IsFalse(dmRelationship.Generated.Value);
            //---------------Execute Test ----------------------
            control.Relationship = dmRelationship;
            //---------------Test Result -----------------------
            Assert.IsTrue(control.Enabled);
            IGridControl gridControl = control.SelectorAndBOEditorControl;
            Assert.IsTrue(gridControl.AllowUsersToAddBO);
            Assert.IsTrue(gridControl.AllowUsersToDeleteBO);
            Assert.IsTrue(gridControl.AllowUsersToEditBO);
        }

        [Test]
        public void TestSetBusinessObject_Generated_SetsPermissionOnEditorControl()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = TestUtilsShared.CreateSavedRelationshipInfoWithTwoRelatedProperties();
            dmRelationship.Generated = true;
            DMRelatedPropertiesControl control =
                new DMRelatedPropertiesControl(new ControlFactoryWin());
            //---------------Assert Precondition----------------
            Assert.IsTrue(dmRelationship.Generated.Value);
            //---------------Execute Test ----------------------
            control.Relationship = dmRelationship;
            //---------------Test Result -----------------------
            Assert.IsTrue(control.Enabled);
            IGridControl gridControl = control.SelectorAndBOEditorControl;
            Assert.IsFalse(gridControl.AllowUsersToAddBO);
            Assert.IsFalse(gridControl.AllowUsersToDeleteBO);
            Assert.IsFalse(gridControl.AllowUsersToEditBO);
        }

        [Test]
        public void Test_Relationship_SetsUpOwnerColumnLookupItems_WhenNotNullRelationship_ShouldHaveAllOwnerProps()
        {
            //---------------Set up test pack-------------------
            DMRelationship relationship;
            DMRelatedPropertiesControl control = GetRelationshipControlWithOwnerClassWithTwoProps(out relationship);
            //---------------Assert Precondition----------------
            Assert.IsNull(control.Relationship);
            Assert.IsNotNull(relationship.OwnerClass);
            Assert.AreEqual(2, relationship.OwnerClass.Properties.Count);
            //---------------Execute Test ----------------------
            control.Relationship = relationship;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(2, control, "PropertyID");
        }

        [Test]
        public void Test_Relationship_SetsUpOwnerColumnLookupItems_WhenNotNullRelationship_ShouldHaveAllOwnerProps_InclSuperclassProps()
        {
            //---------------Set up test pack-------------------
            DMRelationship relationship;
            DMRelatedPropertiesControl control = GetRelationshipControlWithOwnerClassWithTwoProps(out relationship);
            DMClass ownerClass = (DMClass) relationship.ClassDM;
            DMClass superClass = TestUtilsShared.CreateUnsavedValidDMClass(ownerClass.Solution);
            TestUtilsShared.CreateUnsavedValidDMProperty(superClass);
            TestUtilsShared.CreateUnsavedValidDMProperty(superClass);
            ownerClass.InheritanceSuperClassRelationship = new DMInheritanceRelationship
            {
                SuperClass = superClass,
                InheritanceType = ORMapping.ClassTableInheritance
            };
            //---------------Assert Precondition----------------
            Assert.IsNull(control.Relationship);
            Assert.AreEqual(2, ownerClass.Properties.Count);
            Assert.AreEqual(2, superClass.Properties.Count);
            //---------------Execute Test ----------------------
            control.Relationship = relationship;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(4, control, "PropertyID");
        }

        [Test]
        public void Test_Relationship_SetsUpOwnerColumnLookupItems_WhenNullRelationship_ShouldHaveNoItems()
        {
            //---------------Set up test pack-------------------
            DMRelationship relationship;
            DMRelatedPropertiesControl control = GetRelationshipControlWithOwnerClassWithTwoProps(out relationship);
            control.Relationship = relationship;
            //---------------Assert Precondition----------------
            AssertColumnComboBoxItems(2, control, "PropertyID");
            //---------------Execute Test ----------------------
            control.Relationship = null;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(0, control, "PropertyID");
        }

        private DMRelatedPropertiesControl GetRelationshipControlWithOwnerClassWithTwoProps(out DMRelationship relationship)
        {
            TestUtilsDMProperty.CreateSavedDMProperty();
            TestUtilsDMProperty.CreateSavedDMProperty();
            TestUtilsDMProperty.CreateSavedDMProperty();
            relationship = TestUtilsShared.CreateSavedRelationshipInfoWithTwoRelatedProperties();
            return new DMRelatedPropertiesControl(new ControlFactoryWin());
        }

        [Test]
        public void Test_Relationship_SetsUpOwnerColumnLookupItems_WhenRelationshipWithNullOwner_ShouldHaveNoItems()
        {
            //---------------Set up test pack-------------------
            DMRelationship relationship;
            DMRelatedPropertiesControl control = GetRelationshipControlWithOwnerClassWithTwoProps(out relationship);
            DMRelationship relationship2 = TestUtilsDMRelationship.CreateUnsavedDefaultDMRelationship();
            control.Relationship = relationship;
            //---------------Assert Precondition----------------
            Assert.IsNull(relationship2.OwnerClass);
            AssertColumnComboBoxItems(2, control, "PropertyID");
            //---------------Execute Test ----------------------
            control.Relationship = relationship2;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(0, control, "PropertyID");
        }

        // ====================================== Related Class Combo =========================================

        private static DMRelationship GetRelationshipWithRelatedClassWith3Props(out DMClass relatedClass, out DMRelatedPropertiesControl control)
        {
            TestUtilsDMProperty.CreateSavedDMProperty();
            TestUtilsDMProperty.CreateSavedDMProperty();
            TestUtilsDMProperty.CreateSavedDMProperty();
            DMRelationship relationship = TestUtilsShared.CreateUnsavedRelationshipInfoWithTwoRelatedProperties();
            control = new DMRelatedPropertiesControl(new ControlFactoryWin());
            relatedClass = (DMClass) relationship.RelatedClass;
            relatedClass.Properties.CreateBusinessObject();
            relatedClass.Properties.CreateBusinessObject();
            relatedClass.Properties.CreateBusinessObject();
            return relationship;
        }

        [Test]
        public void Test_Relationship_SetsUpRelatedColumnLookupItems_WhenNotNullRelationship_ShouldHaveAllRelatedClassProps()
        {
            //---------------Set up test pack-------------------
            DMClass relatedClass;
            DMRelatedPropertiesControl control;
            DMRelationship relationship = GetRelationshipWithRelatedClassWith3Props(out relatedClass, out control);
            //---------------Assert Precondition----------------
            Assert.IsNull(control.Relationship);
            Assert.AreEqual(3, relatedClass.Properties.Count);
            //---------------Execute Test ----------------------
            control.Relationship = relationship;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(3, control, "ReverseRelationshipProperty.PropertyID");
        }

        [Test]
        public void Test_Relationship_SetsUpRelatedColumnLookupItems_WhenNotNullRelationship_ShouldHaveAllRelatedClassProps_InclSuperclassProps()
        {
            //---------------Set up test pack-------------------
            
            DMClass relatedClass;
            DMRelatedPropertiesControl control;
            DMRelationship relationship = GetRelationshipWithRelatedClassWith3Props(out relatedClass, out control);
            DMClass superClass = TestUtilsShared.CreateUnsavedValidDMClass(relatedClass.Solution);
            TestUtilsShared.CreateUnsavedValidDMProperty(superClass);
            TestUtilsShared.CreateUnsavedValidDMProperty(superClass);
            relatedClass.InheritanceSuperClassRelationship = new DMInheritanceRelationship
                                                      {
                                                          SuperClass = superClass,
                                                          InheritanceType = ORMapping.ClassTableInheritance
                                                      };
            //---------------Assert Precondition----------------
            Assert.IsNull(control.Relationship);
            Assert.AreEqual(3, relatedClass.Properties.Count);
            Assert.AreEqual(2, superClass.Properties.Count);
            //---------------Execute Test ----------------------
            control.Relationship = relationship;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(5, control, "ReverseRelationshipProperty.PropertyID");
        }

        [Test]
        public void Test_Relationship_SetsUpRelatedColumnLookupItems_WhenNullRelationship_ShouldHaveNoItems()
        {
            //---------------Set up test pack-------------------
            DMClass relatedClass;
            DMRelatedPropertiesControl control;
            DMRelationship relationship = GetRelationshipWithRelatedClassWith3Props(out relatedClass, out control);
            control.Relationship = relationship;
            //---------------Assert Precondition----------------
            AssertColumnComboBoxItems(3, control, "ReverseRelationshipProperty.PropertyID");
            //---------------Execute Test ----------------------
            control.Relationship = null;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(0, control, "ReverseRelationshipProperty.PropertyID");
        }

        [Test]
        public void Test_Relationship_SetsUpRelatedColumnLookupItems_WhenRelationshipWithNullRelatedClass_ShouldHaveNoItems()
        {
            //---------------Set up test pack-------------------
            DMClass relatedClass;
            DMRelatedPropertiesControl control;
            DMRelationship relationship = GetRelationshipWithRelatedClassWith3Props(out relatedClass, out control);
            control.Relationship = relationship;

            DMRelationship relationship2 = TestUtilsDMRelationship.CreateUnsavedDefaultDMRelationship();

            //---------------Assert Precondition----------------
            Assert.IsNull(relationship2.RelatedClass);
            AssertColumnComboBoxItems(3, control, "ReverseRelationshipProperty.PropertyID");
            //---------------Execute Test ----------------------
            control.Relationship = relationship2;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(0, control, "ReverseRelationshipProperty.PropertyID");
        }

        [Test]
        public void Test_Relationship_WithNullRelatedClass_WhenSetRelationshipsRelatedClass_ShouldHaveRelatedClassProps()
        {
            //---------------Set up test pack-------------------
            DMClass relatedClass;
            DMRelatedPropertiesControl control;
            DMRelationship relationship = GetRelationshipWithRelatedClassWith3Props(out relatedClass, out control);
            relationship.RelatedClass = null;
            control.Relationship = relationship;
            //---------------Assert Precondition----------------
            Assert.IsNull(relationship.RelatedClass);
            Assert.AreEqual(3, relatedClass.Properties.Count);
            AssertColumnComboBoxItems(0, control, "ReverseRelationshipProperty.PropertyID");
            //---------------Execute Test ----------------------
            relationship.RelatedClass = relatedClass;
            //---------------Test Result -----------------------
            AssertColumnComboBoxItems(3, control, "ReverseRelationshipProperty.PropertyID");
        }

        [Test]
        public void Test_Relationship_WithRelatedClass_WhenGetsNullRelatedClass_ShouldHaveRelatedClassProps()
        {
            //---------------Set up test pack-------------------
            DMClass relatedClass;
            DMRelatedPropertiesControl control;
            DMRelationship relationship = GetRelationshipWithRelatedClassWith3Props(out relatedClass, out control);
            control.Relationship = relationship;
            //---------------Assert Precondition----------------
            Assert.IsNotNull(relationship.RelatedClass);
            Assert.AreEqual(3, relatedClass.Properties.Count);
            AssertColumnComboBoxItems(3, control, "ReverseRelationshipProperty.PropertyID");
            //---------------Execute Test ----------------------
            relationship.RelatedClass = null;
            //---------------Test Result -----------------------
            Assert.IsNull(relationship.RelatedClass);
            AssertColumnComboBoxItems(0, control, "ReverseRelationshipProperty.PropertyID");
        }

        [Test]
        public void Test_Relationship_WithRelatedClass_WhenGetsDifferentRelatedClass_ShouldHaveRelatedClassProps()
        {
            //---------------Set up test pack-------------------
            DMClass relatedClass;
            DMRelatedPropertiesControl control;
            DMRelationship relationship = GetRelationshipWithRelatedClassWith3Props(out relatedClass, out control);
            control.Relationship = relationship;
            DMClass newRelatedClass = GetClassWith5Properties();
            //---------------Assert Precondition----------------
            Assert.AreSame(relatedClass, relationship.RelatedClass);
            Assert.AreEqual(3, relatedClass.Properties.Count);
            Assert.AreEqual(5, newRelatedClass.Properties.Count);
            AssertColumnComboBoxItems(3, control, "ReverseRelationshipProperty.PropertyID");
            //---------------Execute Test ----------------------
            relationship.RelatedClass = newRelatedClass;
            //---------------Test Result -----------------------
            Assert.AreSame(newRelatedClass, relationship.RelatedClass);
            AssertColumnComboBoxItems(5, control, "ReverseRelationshipProperty.PropertyID");
        }

        private static DMClass GetClassWith5Properties()
        {
            DMClass dmClass = TestUtilsDMClass.CreateUnsavedValidDMClass();
            dmClass.Properties.CreateBusinessObject();
            dmClass.Properties.CreateBusinessObject();
            dmClass.Properties.CreateBusinessObject();
            dmClass.Properties.CreateBusinessObject();
            dmClass.Properties.CreateBusinessObject();
            return dmClass;
        }
    }
}